package com.hfast.fakenotification;

import android.app.Activity;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.Vibrator;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import com.hfast.fakenotification.R;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.SmackAndroid;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * Messaging format: <tag></tag>
 * There are four tags: device, type, sender, and content
 * device is either "android" or "pebble" (case sensitive)
 * type is either "call" or "text"
 * e.g. <device>android</device><type>text</type><sender>Carl</sender><content>Hello Android</content>
 */

public class Main extends Activity implements MessageDisplayInterface {

    //These will need to be changed depending on server and user info
    public static final String HOST = "192.168.0.197"; //wireless IPv4 address, 192.168.0.184 is wayne's address
    public static final int PORT = 5222; //default port
    public static final String USERNAME = "android";
    public static final String PASSWORD = "12345";

    public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
    public final static String EXTRA_NUMBER = "com.example.myfirstapp.NUMBER";
    public final static String EXTRA_CALLER = "com.example.myfirstapp.CALLER";
    public final static String EXTRA_SENDER = "com.example.myfirstapp.SENDER";
    public static final String TEXT_STAT = "TextStatus";

    private TextView text;
    private XMPPConnection connection;
    private boolean calling = false;
    private String[] senders;
    private List<TextMessage> textList = new ArrayList<TextMessage>();
    private MyAdapter listAdapter;
    private double sendTime;

    PowerManager.WakeLock TempWakeLock;
    PowerManager.WakeLock wakeLock;
    KeyguardManager keyguardManager;
    KeyguardManager.KeyguardLock keyguardLock;
    ListView listView;
    NotificationManager mNotificationManager;



    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        System.out.println("Creating Main");

        PowerManager TempPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        TempWakeLock = TempPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TempWakeLock");
        if (!TempWakeLock.isHeld()) {
            TempWakeLock.acquire();
        }
        //initiates Smack client and calls up connect function on a separate thread
        SmackAndroid.init(getApplicationContext());
        Connect connect = new Connect();
        connect.execute();

        listAdapter = new MyAdapter(this, textList);
        listView = (ListView) findViewById(R.id.inboxList);
        listView.setAdapter(listAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent resultIntent = new Intent(getApplicationContext(), DisplayNewMessage.class);
                TextMessage text = (TextMessage) parent.getItemAtPosition(position);
                resultIntent.putExtra(EXTRA_SENDER, text.getSender());
                resultIntent.putExtra(EXTRA_MESSAGE, text.getRecentMessage());
                mNotificationManager.cancel(text.getSender(),1);
                startActivity(resultIntent);
            }
        });


//        SharedPreferences textStat = getSharedPreferences(TEXT_STAT, 0);
//        boolean isThereText = textStat.getBoolean("isThereText", false);
//        if(isThereText){
//            String message = textStat.getString("message", "");
//            String sender = textStat.getString("sender", "");
//
//            // Creates an explicit intent for an Activity in your app
//            Intent resultIntent = new Intent(this, DisplayNewMessage.class);
//            resultIntent.putExtra(EXTRA_MESSAGE, message);
//            resultIntent.putExtra(EXTRA_SENDER, sender);
//
//            startActivity(resultIntent);
//        }

    }

    @Override
    protected void onStart() {
        super.onStart();
        System.out.println("Starting Main");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        System.out.println("Restarting Main");
    }

    @Override
    protected void onPause() {
        super.onPause();
        System.out.println("Pausing Main");
    }

    @Override
    protected void onStop() {
        super.onStop();
        System.out.println("Stopping Main");
    }

    //display functions (to be set up by other ppl)
    @Override
    public void displayAndroidCall(String caller, String number) {
        Intent resultIntent = new Intent(this, PhoneCall.class);
        resultIntent.putExtra(EXTRA_CALLER, caller);
        resultIntent.putExtra(EXTRA_NUMBER, number);

        // Wake the phone up
//        PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
//        wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "TAG");
//        wakeLock.acquire();
//        // Unlock phone
//        keyguardManager = (KeyguardManager) getApplicationContext().getSystemService(Context.KEYGUARD_SERVICE);
//        keyguardLock =  keyguardManager.newKeyguardLock("TAG");
//        keyguardLock.disableKeyguard();
        calling = true;

        startActivity(resultIntent);
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("Resuming Main");
        if(calling) {
////            keyguardLock.reenableKeyguard();
//            wakeLock.release();
            calling = false;
        }
    }

    @Override
    public void displayAndroidText(String sender, String message) {

        Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle(sender)
                .setContentText(message);



        // Creates an explicit intent for an Activity in your app
        Intent resultIntent = new Intent(this, DisplayNewMessage.class);

        //
        boolean contains = false;
        if(textList.isEmpty()){
            textList.add(0,new TextMessage(sender, message));
            resultIntent.putExtra(EXTRA_MESSAGE, message);
            resultIntent.putExtra(EXTRA_SENDER, sender);
            listAdapter.notifyDataSetChanged();
        } else{
            TextMessage textMessage = null;
            for (TextMessage text : textList){
                if(sender.contentEquals(text.getSender())){
                    text.addMessage(message);
                    resultIntent.putExtra(EXTRA_MESSAGE, text.getRecentMessage()); //change to getAllMessages() once we figure out how to display more than one message
                    resultIntent.putExtra(EXTRA_SENDER, text.getSender());
                    textMessage = text;
                    contains = true;
                }
            }
            if(contains){
                textList.remove(textMessage);
                textList.add(0, textMessage);
                listAdapter.notifyDataSetChanged();
            } else {
                textList.add(0,new TextMessage(sender, message));
                resultIntent.putExtra(EXTRA_MESSAGE, message);
                resultIntent.putExtra(EXTRA_SENDER, sender);
                listAdapter.notifyDataSetChanged();
            }

        }

        // Creates the vibrate, color flash, and tone
        Vibrator vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
        vibrator.vibrate(500);

        Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
        r.play();
        builder.setAutoCancel(true);
        builder.setLights(Color.BLUE, 500, 500);

        // The stack builder object will contain an artificial back stack for the started Activity.
        // This ensures that navigating backward from the Activity leads out of your application to the Home screen.
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        // Adds the back stack for the Intent (but not the Intent itself)
//        stackBuilder.addParentStack(DisplayNewMessage.class);

        // Adds the Intent that starts the Activity to the top of the stack
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent =
                stackBuilder.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

        builder.setContentIntent(resultPendingIntent);
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(sender,1, builder.build());

//        SharedPreferences settings = getSharedPreferences(TEXT_STAT, 0);
//        SharedPreferences.Editor editor = settings.edit();
//        editor.putBoolean("isThereText", true);
//        editor.putString("message", message);
//        editor.putString("sender", sender);
//        editor.commit();
//        startActivity(resultIntent);



//            text.append("Receiving text to Android\nSender: " + sender + "\nMessage: " + message + "\n\n");

    }

    @Override
    public void displayPebbleCall(String caller, String number) {
//        text.append("Receiving call to Pebble\nCaller: " + caller + "\nNumber: " + number + "\n\n");
    }

    @Override
    public void displayPebbleText(String sender, String message) {
//        text.append("Receiving text to Pebble\nSender: " + sender + "\nMessage: " + message + "\n\n");
    }




    private class Connect extends AsyncTask<Void, Void, XMPPConnection> {

        @Override
        protected XMPPConnection doInBackground(Void... params) {

            //set up connection configurations

            ConnectionConfiguration configuration = new ConnectionConfiguration(HOST, PORT);
            configuration.setDebuggerEnabled(true);
            configuration.setCompressionEnabled(true);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                configuration.setTruststoreType("AndroidCAStore");
                configuration.setTruststorePassword(null);
                configuration.setTruststorePath(null);
            } else {
                configuration.setTruststoreType("BKS");
                String path = System.getProperty("javax.net.ssl.trustStore");
                if (path == null)
                    path = System.getProperty("java.home") + File.separator + "etc"
                            + File.separator + "security" + File.separator
                            + "cacerts.bks";
                configuration.setTruststorePath(path);
            }

            XMPPConnection conn = new XMPPConnection(configuration);


            //attempts to connect and login to XMPP server
            try {
                conn.connect();
                conn.login(USERNAME, PASSWORD);
            } catch (XMPPException e){
                conn = null;
                e.printStackTrace();
            }

            if(conn.isConnected()){
                System.out.println("isConnected");
            } else{
                System.out.println("notConnected");
            }

            if(conn.isAuthenticated()){
                System.out.println("isLoggedIn");
            } else {
                System.out.println("notLoggedIn");
            }

            //set status to available
            Presence presence = new Presence(Presence.Type.available);
            conn.sendPacket(presence);

            return conn; //returns to onPostExecute
        }

        @Override
        protected void onPostExecute(XMPPConnection xmppConnection) {

            super.onPostExecute(xmppConnection);
            connection = xmppConnection;

            //Sets up a Listener to receive any incoming messages
            PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
            connection.addPacketListener(new PacketListener() {

                public void processPacket(Packet packet) {
                    final Message message = (Message) packet;
                    System.out.println("Received message:" + message.getBody());
                    long time = (System.currentTimeMillis());
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            sortMessage(message.getBody());
                        }
                    });
                    double receiveTime = time;
                    try {
                        receiveTime += SntpClient.main("tick.utoronto.ca");
                    } catch (IOException e){
                        e.printStackTrace();
                    }
                    String sendTimeS[] = extract(message.getBody(),new String[]{"sendTime"});
                    sendTime = Double.parseDouble(sendTimeS[0]);
                    Double timeDelay = receiveTime - sendTime;
                    System.out.println("Time Delay: " + new DecimalFormat("0.00").format(timeDelay) + " ms");
                }
            }, filter);
        }
    }


    //Parses and sorts messages passed from the Listener
    public void sortMessage(String message){
        String[] tags = new String[]{"device", "type", "sender", "content"};
        String[] parsedMessage = extract(message, tags);
        String device = parsedMessage[0];
        String type = parsedMessage[1];
        String sender = parsedMessage[2];
        String content = parsedMessage[3];
        if(sender == null){
            System.out.println("Error: incorrect sender tag");
            return;
        }
        if(content == null){
            System.out.println("Error: incorrect content tag");
            return;
        }


        //determining which type of display is required
        if(device.contentEquals("android") && type.contentEquals("call")) {
            displayAndroidCall(sender, content);

        } else if(device.contentEquals("android") && type.contentEquals("text")) {
            displayAndroidText(sender, content);

        } else if(device.contentEquals("pebble") && type.contentEquals("call")) {
            displayPebbleCall(sender, content);

        } else if(device.contentEquals("pebble") && type.contentEquals("text")) {
            displayPebbleText(sender, content);

        } else{
            System.out.println("Error: incorrect device or type tag");
        }
    }

    //extracts the content from the tags into an array of strings
    public String[] extract(String message, String tags[]){
        int length = tags.length;
        String[] content = new String[length];
        for (int i = 0; i < length; i++){
            int index1 = message.indexOf("<" + tags[i] + ">");
            if (index1<0) break;
            index1 += (2 + tags[i].length());
            int index2 = message.indexOf("</" + tags[i] + ">");
            if (index2<0) break;
            content[i] = message.substring(index1, index2);
        }
        return content;
    }


    //Prevent app from calling onDestroy() when back button is pressed.
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event)
    {

        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)
        {

            this.moveTaskToBack(true);
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("Destroying Main");
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if(connection != null) {
                    try {
                        connection.disconnect();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread mythread = new Thread(runnable);
        mythread.start();
        TempWakeLock.release();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
